package cn.darkhorse.mesadmin.controller.alarm;


import cn.darkhorse.alarm.dto.AlarmSettingPonitTablesDTO;
import cn.darkhorse.alarm.dto.PointTableParamsDTO;
import cn.darkhorse.alarm.pojo.AlarmParameterSettings;
import cn.darkhorse.alarm.service.AlarmParameterSettingsService;
import cn.darkhorse.alarm.service.alarm.BaseAlarm;
import cn.darkhorse.device.iot.constant.IotConstant;
import cn.darkhorse.device.pojo.IotPointTable;
import cn.darkhorse.device.pojo.MesDevice;

import cn.darkhorse.device.service.IotPointTableService;
import cn.darkhorse.device.service.MesDeviceParamMappingService;
import cn.darkhorse.device.service.MesDeviceService;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import lombok.Data;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 设备参数设置控制器
 * @author yuanjun
 * @since 2023-04-10
 */
@RestController
@RequestMapping("/alarm/alarmParameterSettings")
public class AlarmParameterSettingsController extends BaseController {
    public static final String REDIS_KEY_REFRESH = "refresh";

    @Resource
    private AlarmParameterSettingsService alarmParameterSettingsService;

    @Resource
    private MesDeviceParamMappingService mesDeviceParamMappingService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private IotPointTableService iotPointTableService;
    @Resource
    private RedisCache redisCache;
    @Resource
    private MesDeviceService deviceService;



    /**
     * 设置刷新标记，通知数据处理程序刷新内存数据
     */
    private void setRefreshFlag() {
        stringRedisTemplate.opsForList().leftPush(REDIS_KEY_REFRESH,"true");
    }

    /**
     * 查看参数设置
     * @param id 记录id
     * @return
     */
    @RequestMapping("/view")
    public AjaxResult view(Long id) {
        Map<String, Object> result = new HashMap<>();
        AlarmParameterSettings settings = alarmParameterSettingsService.getById(id);
        if(null == settings){
            return AjaxResult.success(result);
        }
        IotPointTable pointTable = iotPointTableService.getById(settings.getPointTableId());
        String newAlarmMessage = "";
        if(StringUtils.isNotBlank(settings.getAlarmMessage()) &&null != pointTable){
            JSONArray newMessageArray = new JSONArray();
            String alarmMessage = settings.getAlarmMessage();
            Integer parameterType = settings.getParameterType();
            if(BaseAlarm.ALARM_PARAMETER_TYPE_SWITCH.equals(parameterType)||
                    BaseAlarm.ALARM_PARAMETER_TYPE_ENUMERATION.equals(parameterType)){
                JSONArray messageArray = JSONArray.parse(alarmMessage);
                JSONArray extraArray = JSONArray.parse(pointTable.getExtraJson());
                for(Object message :messageArray){
                    JSONObject meObj=JSONObject.parse(message.toString());
                    for(Object extra :extraArray){
                        JSONObject exObj=JSONObject.parse(extra.toString());
                        if(meObj.getString("value").equals(exObj.getString("label"))){
                            meObj.put("label",exObj.getString("value"));
                        }
                    }
                    newMessageArray.add(meObj);
                }
            }
            newAlarmMessage = newMessageArray.isEmpty()?alarmMessage:newMessageArray.toString();
        }
        result = BeanUtil.beanToMap(settings);
        result.put("extraJson",pointTable.getExtraJson());
        result.put("newAlarmMessage",newAlarmMessage);
        return AjaxResult.success(result);
    }


    /**
     * 保存参数设置信息
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/save")
    public AjaxResult save(@RequestBody AlarmParameterSettings entity) {
        AlarmParameterSettings settings = alarmParameterSettingsService.getById(entity.getId());
        if (settings == null){
            return AjaxResult.error("参数设置信息不存在");
        }
        // 校验自定义参数是否已经存在
        if (StringUtils.isNotBlank(entity.getCustomParameterName())) {
            LambdaQueryWrapper<AlarmParameterSettings> queryWrapper = new LambdaQueryWrapper<AlarmParameterSettings>();
            queryWrapper .eq(AlarmParameterSettings::getGatewayDeviceId, entity.getGatewayDeviceId());
            if (entity.getId() != null) {
                queryWrapper.ne(AlarmParameterSettings::getId, entity.getId());
            }
            queryWrapper.eq(AlarmParameterSettings::getCustomParameterName, entity.getCustomParameterName().trim());
            List<AlarmParameterSettings> list = alarmParameterSettingsService.list(queryWrapper);
            if (list.size() > 0) {
                throw new ServiceException(String.format("【%s】自定义参数名称已存在，请检查后输入",entity.getCustomParameterName().trim()));
            }
        }
      //告警内容校验
        alarmMessageCheck(entity);


        // 保存或更新数据，默认不能更新null值，需要特殊处理一下
       LambdaUpdateWrapper<AlarmParameterSettings> updateWrapper = new LambdaUpdateWrapper<>();
         /*if (null == entity.getAlarmType()) {
            updateWrapper.set(AlarmParameterSettings::getAlarmType,null);
        }
        if (null == entity.getIntervalTime()) {
            updateWrapper.set(AlarmParameterSettings::getIntervalTime, null);
        }*/
        updateWrapper.eq(AlarmParameterSettings::getId,entity.getId());

        boolean result = alarmParameterSettingsService.update(entity, updateWrapper);
        setRefreshFlag();
        //修改  清除缓存
        redisCache.deleteObject(IotConstant.CACHE_MQTT_ALARM_PARAMS+settings.getGatewayDeviceId());
        return AjaxResult.success(result);
    }

    private void alarmMessageCheck(AlarmParameterSettings entity){
        String alarmMessages = entity.getAlarmMessage();
        if(StringUtils.isBlank(alarmMessages)){
            return;
        }
        Set<Object> repeatValue = new HashSet<>();
        JSONArray array = JSONArray.parse(alarmMessages);
        Integer parameterType = entity.getParameterType();
        if(BaseAlarm.ALARM_PARAMETER_TYPE_NUMERICAL.equals(parameterType)){
            if(BaseAlarm.ALARM_LIMIT_VALUE.equals(entity.getAlarmType())){
                BigDecimal maxValue;
                BigDecimal  minValue;
                JSONObject limitValue = array.getJSONObject(0);
                JSONObject limitValue2 = array.getJSONObject(1);
                Object value = limitValue.get("maxValue");
                if(null == value){
                  maxValue = limitValue2.getBigDecimal("maxValue");
                    minValue = limitValue.getBigDecimal("minValue");
                }else {
                    minValue = limitValue2.getBigDecimal("minValue");
                    maxValue = limitValue.getBigDecimal("maxValue");
                }
                if(maxValue.compareTo(minValue) < 1){
                    throw new ServiceException("参数值上限值小于下限值！请检查！");
                }
            }
        }
        if(BaseAlarm.ALARM_PARAMETER_TYPE_CHARACTER.equals(parameterType) || BaseAlarm.ALARM_CONTINUOUS_VALUE.equals(entity.getAlarmType())){
            for(int i = 0;i<array.size();i++){
                JSONObject alarmMessage = array.getJSONObject(i);
                if(!repeatValue.add(alarmMessage.get("value"))){
                    throw new ServiceException("告警参数值重复！请检查！");
                }
            }
        }

    }


    /**
     * 批量保存参数
     * @param ptParmas
     * @return
     */
    @PostMapping("/saves")
    public AjaxResult saveParams(@RequestBody List<PointTableParamsDTO> ptParmas) {
        String gatewayDeviceId = alarmParameterSettingsService.saveParams(ptParmas);
        if(StringUtils.isNotBlank(gatewayDeviceId)){
            //修改  清除缓存
            redisCache.deleteObject(IotConstant.CACHE_MQTT_ALARM_PARAMS+gatewayDeviceId);
        }
        return AjaxResult.success();
    }

    /**
     * 设置参数信息-----选择参数列表
     * @param deviceId
     * @return
     */
    @RequestMapping("/parameter/list")
    public TableDataInfo parameterList(Long deviceId,String piontName) {
        startPage();
        List<AlarmSettingPonitTablesDTO> paramsList = alarmParameterSettingsService.settingPonitTableList(null,
                deviceId,piontName);
        return getDataTable(paramsList);
    }

    /**
     * 告警规则列表
     * @param deviceId
     * @return
     */
    @RequestMapping("/rule/list")
    public TableDataInfo alarmRuleList(Long deviceId) {
        startPage();
//        List<MesDevice> deviceList = deviceService.lambdaQuery().eq(MesDevice::getParentId, deviceId).list();
//        // 子设备逻辑
//        ArrayList<Long> ids = new ArrayList<>();
//        ids.add(deviceId);
//        if (!deviceList.isEmpty()) {
//            List<Long> collect = deviceList.stream().map(MesDevice::getId).collect(Collectors.toList());
//            ids.addAll(collect);
//        }
        LambdaQueryWrapper<AlarmParameterSettings> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(AlarmParameterSettings::getDeviceId,deviceId);
        queryWrapper.isNotNull(AlarmParameterSettings::getAlarmType);
        List<AlarmParameterSettings> parameterSettings = alarmParameterSettingsService.list(queryWrapper);
        return getDataTable(parameterSettings);
    }

    /**
     * 规则查看报警内容
     * @param parameterSettingId
     * @return
     */
    @RequestMapping("/rule/view")
    public AjaxResult alarmRuleView(Long parameterSettingId) {
        List<RuleAlarmVO> result = new ArrayList<>();
        AlarmParameterSettings parameterSetting = alarmParameterSettingsService.getById(parameterSettingId);
         if(null == parameterSetting || StringUtils.isBlank(parameterSetting.getAlarmMessage())){
             return AjaxResult.success(result);
         }
        String alarmMessage = parameterSetting.getAlarmMessage();
        Integer parameterType = parameterSetting.getParameterType();
        Integer alarmType = parameterSetting.getAlarmType();
        IotPointTable pointTable = iotPointTableService.getById(parameterSetting.getPointTableId());
        Map<String, String> extraJsonMap = pointExtraJsonMap(pointTable.getExtraJson());
        JSONArray mesArray = JSONArray.parse(alarmMessage);
        for(int i = 0;i<mesArray.size();i++){
            JSONObject mes = mesArray.getJSONObject(i);
            RuleAlarmVO vo = new RuleAlarmVO();
            vo.setMes(mes.getString("msg"));
            vo.setValue(mes.getString("value"));
            vo.setLabel(mes.getString("value"));
            if(BaseAlarm.ALARM_PARAMETER_TYPE_SWITCH.equals(parameterType) || BaseAlarm.ALARM_PARAMETER_TYPE_ENUMERATION.equals(parameterType)){
                if(StringUtils.isNotBlank(extraJsonMap.get(mes.getString("value")))){
                    vo.setLabel(extraJsonMap.get(mes.getString("value")));
                }
            }
            if(BaseAlarm.ALARM_PARAMETER_TYPE_NUMERICAL.equals(parameterType)){
                if(BaseAlarm.ALARM_LIMIT_VALUE.equals(alarmType)){
                    String minValue = mes.getString("minValue");
                    if(StringUtils.isBlank(minValue)){
                        vo.setValue(mes.getString("maxValue"));
                        vo.setLabel("上限报警值");
                    }else {
                        vo.setValue(minValue);
                        vo.setLabel("下限报警值");
                    }
                }
            }
            result.add(vo);
        }
        return AjaxResult.success(result);
    }

    /**
     * 电表属性解析成map
     * @param extraJson
     * @return
     */
    private Map<String,String> pointExtraJsonMap(String extraJson){
        Map<String,String> paramsDescriptionMap = new HashMap<>();
        JSONArray parse = JSONArray.parse(extraJson);
        for(int i = 0;i<parse.size();i++){
            JSONObject params = parse.getJSONObject(i);
            paramsDescriptionMap.put(params.getString("label"), params.getString("value"));
        }
        return paramsDescriptionMap;
    }



    @Data
    class RuleAlarmVO{
        private String label;
        private String mes;
        private String value;
    }






    /**
     * 删除告警规则
     * @param id
     * @return
     */
    @RequestMapping("/rule/del")
    public AjaxResult deleteAlarmRule(Long id) {
        LambdaUpdateWrapper<AlarmParameterSettings>  updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(AlarmParameterSettings::getId,id)
                    .set(AlarmParameterSettings::getAlarm,null)
                    .set(AlarmParameterSettings::getAlarmMessage,null)
                    .set(AlarmParameterSettings::getAlarmFrequency,null)
                    .set(AlarmParameterSettings::getIntervalTime,null)
                    .set(AlarmParameterSettings::getRemarks,null)
                    .set(AlarmParameterSettings::getAlarmType,null)
                    .set(AlarmParameterSettings::getShowOrder,null);
        boolean b = alarmParameterSettingsService.update(updateWrapper);
        return AjaxResult.success(b);
    }











    /**
     * 修改设备参数的显示顺序
     * @param  ids：alarm_parameter_settings表的id，用英文逗号隔开
     * @return
     */
    @PostMapping("/update/order")
    public AjaxResult updateShowOrder(String ids) {
        String[] idArr = ids.split(",");
        List<AlarmParameterSettings> settingsList = new ArrayList<>();

        for (int i = 0; i < idArr.length; i++) {
            Long id = Long.parseLong(idArr[i]);
            AlarmParameterSettings settings = new AlarmParameterSettings();
            settings.setId(id);settings.setShowOrder(i);
            settingsList.add(settings);
        }

        boolean result = alarmParameterSettingsService.updateBatchById(settingsList);

        return AjaxResult.success(result);
    }













}

